package com.lekang.web.controller.system;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Date;
import java.util.List;
import java.util.Set;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lekang.common.annotation.Anonymous;
import com.lekang.controller.PhoneNumberController;
import com.lekang.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.lekang.common.constant.Constants;
import com.lekang.common.core.domain.AjaxResult;
import com.lekang.common.core.domain.entity.SysMenu;
import com.lekang.common.core.domain.entity.SysUser;
import com.lekang.common.core.domain.model.LoginBody;
import com.lekang.common.core.domain.model.LoginUser;
import com.lekang.common.core.text.Convert;
import com.lekang.common.utils.DateUtils;
import com.lekang.common.utils.SecurityUtils;
import com.lekang.common.utils.StringUtils;
import com.lekang.framework.web.service.SysLoginService;
import com.lekang.framework.web.service.SysPermissionService;
import com.lekang.framework.web.service.TokenService;
import com.lekang.system.service.ISysConfigService;
import com.lekang.system.service.ISysMenuService;

/**
 * 登录验证
 *
 * @author ruoyi
 */
@RestController
public class SysLoginController
{
    @Autowired
    private SysLoginService loginService;

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;




    private static final String APP_ID = "wx45e45510a4a65a29";
    private static final String APP_SECRET = "073ce0e2dcffe8bdf82edd0a582a0b23";

    // 获取 access_token 的接口
    private static final String ACCESS_TOKEN_URL =
            "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    // 获取手机号的接口
    private static final String GET_PHONE_NUMBER_URL =
            "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s";

    @PostMapping("/wxphoneLogin")
    @Anonymous
    public AjaxResult getPhoneNumber(@RequestBody PhoneNumberController.PhoneCodeRequest request) {
        String code = request.getCode();
        try {
            // 1. 先获取 access_token
            String accessToken = getAccessToken();

            // 2. 调用获取手机号接口
            String phoneApiUrl = String.format(GET_PHONE_NUMBER_URL, accessToken);

            // 构造 POST 请求体（JSON 格式）
            String jsonBody = String.format("{\"code\":\"%s\"}", code);

            HttpClient httpClient = HttpClient.newHttpClient();
            HttpRequest httpRequest = HttpRequest.newBuilder()
                    .uri(URI.create(phoneApiUrl))
                    .header("Content-Type", "application/json; charset=utf-8")
                    .POST(HttpRequest.BodyPublishers.ofString(jsonBody))
                    .build();

            HttpResponse<String> response = httpClient.send(
                    httpRequest,
                    HttpResponse.BodyHandlers.ofString()
            );

            // 3. 解析微信返回结果
            System.out.println("微信返回原始数据：" + response.body());
            String body = response.body();
            // 从response中解析出手机号
            ObjectMapper objectMapper = new ObjectMapper();
            // 1. 将 JSON 字符串解析成 JsonNode 树
            JsonNode rootNode = objectMapper.readTree(body);
            // 2. 获取 phone_info 节点
            JsonNode phoneInfoNode = rootNode.path("phone_info");
            // 3. 从 phone_info 中提取手机号字段
            String phoneNumber = phoneInfoNode.path("phoneNumber").asText();
            // 从sysuser表查询是否有phone
            SysUser user = sysUserService.selectUserByUserName(phoneNumber);
            // 如果有数据，则直接登录
            if(user!=null){
                System.out.println("直接登录====================");
                return wxLogin(phoneNumber);
            }else{
                System.out.println("先注册，在登录====================");
                // 如果没有数据，则先注册，在登录
                // 1.把数据封装对象，放入数据库
                SysUser sysUser = new SysUser();
                sysUser.setUserName(phoneNumber);
                sysUser.setPhonenumber(phoneNumber);
                sysUser.setNickName("微信用户"+phoneNumber.substring(7));
                // 设置默认密码
                sysUser.setPassword(passwordEncoder.encode("123456"));
                // 给当前新注册的用户设置角色id
                sysUser.setRoleIds(new Long[]{100L});
                sysUser.setDeptId(100L);
                sysUserService.insertUser(sysUser);
                // 2.登录
                return wxLogin(phoneNumber);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new AjaxResult();
        }
    }

    /**
     * 获取 access_token（小程序全局凭证）
     */
    private String getAccessToken() throws Exception {
        String url = String.format(ACCESS_TOKEN_URL, APP_ID, APP_SECRET);

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println("access_token 接口返回：" + response.body());

        // 简单解析 JSON（生产环境建议用 Jackson / Gson）
        // 假设返回格式：{"access_token":"YOUR_TOKEN","expires_in":7200}
        String jsonResponse = response.body();
        for (String line : jsonResponse.split(",")) {
            if (line.contains("access_token")) {
                String token = line.split(":")[1].replace("\"", "").trim();
                return token;
            }
        }
        throw new RuntimeException("无法获取 access_token：" + jsonResponse);
    }

    /**
     * 用于接收前端传来的 code（简单 POJO）
     */
    public static class PhoneCodeRequest {
        private String code;
        // Getter & Setter
        public String getCode() {
            return code;
        }
        public void setCode(String code) {
            this.code = code;
        }
    }
    @GetMapping("/wxlogin")
    public AjaxResult wxLogin(String phone)
    {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.wxlogin(phone);
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }
    @GetMapping("/emaillogin")
    public AjaxResult emailLogin(String email,String emailCode )
    {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.emaillogin(email,emailCode);
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }








    /**
     * 登录方法
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    public AjaxResult login(@RequestBody LoginBody loginBody)
    {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
                loginBody.getUuid());
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }

    @GetMapping("/getwxInfo")
    public AjaxResult getwxInfo()
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);
        if (!loginUser.getPermissions().equals(permissions))
        {
            loginUser.setPermissions(permissions);
            tokenService.refreshToken(loginUser);
        }
        AjaxResult ajax = AjaxResult.success();
        ajax.put("user", user);
        ajax.put("roles", roles);
        ajax.put("permissions", permissions);
        ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
        ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
        return ajax;
    }
    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @GetMapping("getInfo")
    public AjaxResult getInfo()
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);
        if (!loginUser.getPermissions().equals(permissions))
        {
            loginUser.setPermissions(permissions);
            tokenService.refreshToken(loginUser);
        }
        AjaxResult ajax = AjaxResult.success();
        ajax.put("user", user);
        ajax.put("roles", roles);
        ajax.put("permissions", permissions);
        ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
        ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
        return ajax;
    }

    /**
     * 获取路由信息
     *
     * @return 路由信息
     */
    @GetMapping("getRouters")
    public AjaxResult getRouters()
    {
        Long userId = SecurityUtils.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return AjaxResult.success(menuService.buildMenus(menus));
    }

    // 检查初始密码是否提醒修改
    public boolean initPasswordIsModify(Date pwdUpdateDate)
    {
        Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
        return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
    }

    // 检查密码是否过期
    public boolean passwordIsExpiration(Date pwdUpdateDate)
    {
        Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
        if (passwordValidateDays != null && passwordValidateDays > 0)
        {
            if (StringUtils.isNull(pwdUpdateDate))
            {
                // 如果从未修改过初始密码，直接提醒过期
                return true;
            }
            Date nowDate = DateUtils.getNowDate();
            return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
        }
        return false;
    }
}
